/********************************************************************************************/
/* 	\file			rtos.c
 *	\date			
 *	\author			
 *	\model			
 *	\description	
 *	\version
 *
 *********************************************************************************************
 *	\par	Revision History:
 *	<!-----	No.		Date		Revised by		Details	------------------------------------->
 *
 ********************************************************************************************/

/********************************************************************************************/
/*							Include File Section											*/
/********************************************************************************************/
#include <string.h>
#include <stdbool.h>

#include "TypeDef.h"
#include "FreeRTOS.h"
#include "FreeRTOSConfig.h"
#include "task.h"
#include "queue.h"
#include "timers.h"

#include "osif.h"

#include "rtos.h"
#include "rtos_config.h"

#include "pit.h"
#include "linflexd_uart.h"


#include "console.h"

#include "dev_pm.h"
#include "dev_led.h"
#include "dev_cp.h"
/********************************************************************************************/
/*							Macro Definition Section										*/
/********************************************************************************************/
#define OS_MAX_TASK		32
#define OS_MAX_QUEUE	32
#define OS_MAX_SEMA		32
#define OS_MAX_EVENT	16
#define OS_MAX_TIMER	8

#if TSK_ID_MAX > OS_MAX_TASK
#error "Over the maximum number of tasks!!!"
#endif
#if QUEUE_ID_MAX > OS_MAX_QUEUE
#error "Over the maximum number of queues!!!"
#endif
#if EVENT_ID_MAX > OS_MAX_EVENT
#error "Over the maximum number of events!!!"
#endif
#if SEMA_ID_MAX > OS_MAX_SEMA
#error "Over the maximum number of Semaphore!!!"
#endif
/********************************************************************************************/
/*							Type Definition Section											*/
/********************************************************************************************/

/********************************************************************************************/
/*							Enumeration Type Definition Section								*/
/********************************************************************************************/

/********************************************************************************************/
/*							Structure/Union Type Definition Section							*/
/********************************************************************************************/

/********************************************************************************************/
/*							Global Variable Definition Section								*/
/********************************************************************************************/

/********************************************************************************************/
/*							Static Variable Definition Section								*/
/********************************************************************************************/
/* OS object */
static StaticTask_t			OS_Task_Obj[OS_MAX_TASK];
static StaticQueue_t		OS_Queue_Obj[OS_MAX_QUEUE];
//static StaticSemaphore_t	OS_Sema_Obj[OS_MAX_SEMA];
//static StaticEventGroup_t	OS_Event_Obj[OS_MAX_EVENT];
static StaticTimer_t		OS_Timer_Obj[OS_MAX_TIMER];

#if TSK_ID_MAX
static uint32 u32TaskHandle[TSK_ID_MAX];
static uint32 u32TaskStk[TASK_STK_TOTAL];
//static uint32 u32TaskID[TSK_ID_MAX];
#endif
#if QUEUE_ID_MAX
static uint32 u32QueueHandle[QUEUE_ID_MAX];
//static uint32 u32QueueID[QUEUE_ID_MAX];
#endif
#if EVENT_ID_MAX
static uint32 u32EventID[EVENT_ID_MAX];
#endif
#if SEMA_ID_MAX
static uint32 u32SemaphoreID[SEMA_ID_MAX];
#endif
#if CYC_ID_MAX
static uint32 u32CycleHandle[CYC_ID_MAX];
static uint32 u32CycleID[CYC_ID_MAX];
#endif

/********************************************************************************************/
/*							Static Prototype Declaration Section							*/
/********************************************************************************************/
static void RTOS_Cycle_TimerCallback(TimerHandle_t xTimer);
/********************************************************************************************/
/*							ROM Table Section												*/
/********************************************************************************************/

/********************************************************************************************/
/*							Function Definition Section										*/
/********************************************************************************************/

void TSK_Start(void * exinf){
	/* Initialize Console(Printf) */
    LINFLEXD_UART_DRV_Init(INST_LINFLEXD_UART,&linflexd_uart_State,&linflexd_uart6_InitConfig0);
    InitializeConsole();
    /* SystemTick(64Bit(uS) */
    PIT_DRV_InitChannel(INST_PIT,&OS_SystemTickUS_H);
    PIT_DRV_InitChannel(INST_PIT,&OS_SystemTickUS_L);
    PIT_DRV_StartChannel(INST_PIT,OS_SystemTickUS_H.hwChannel);
    PIT_DRV_StartChannel(INST_PIT,OS_SystemTickUS_L.hwChannel);
    /* Initialize PMIC */
	vdPmDevice_Init();
	vdLedDevice_Init();
	vdCpDevice_Init();
	RTOS_TaskDelay(1000);
    //RTOS_TaskDelay(1000);
    RTOS_QueueCreate();
    RTOS_TaskCreate();
    RTOS_CycleCreate();
    
    while(1){
    	portNOP();
        RTOS_TaskDelay(1000);
    }
}
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
	static StaticTask_t			OS_TaskIdle_Obj;
	static uint32 				OS_TaskIdle_Stk[200];

	*ppxIdleTaskTCBBuffer = (StaticTask_t*)(&OS_TaskIdle_Obj);
	*ppxIdleTaskStackBuffer = (StackType_t*)(&OS_TaskIdle_Stk[0]);
	*pulIdleTaskStackSize = (uint32_t)(200);
}
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize )
{
	static StaticTask_t			OS_TaskTimer_Obj;
	//static uint32 				OS_TaskTimer_Stk[200];
	static uint32 				OS_TaskTimer_Stk[4096];

	*ppxTimerTaskTCBBuffer = (StaticTask_t*)(&OS_TaskTimer_Obj);
	*ppxTimerTaskStackBuffer = (StackType_t*)(&OS_TaskTimer_Stk[0]);
	//*pulTimerTaskStackSize = (uint32_t)(200);
	*pulTimerTaskStackSize = (uint32_t)(4096);
}

void RTOS_Init(void){
    static StaticTask_t			OS_TaskStart_Obj;
    static uint32 				OS_TaskStart_Stk[200];
	(void)xTaskCreateStatic((TaskFunction_t)(TSK_Start),
							(const char * const)("Task_Start"),
							(const uint32)200,
							0,
							(UBaseType_t)((13) | portPRIVILEGE_BIT ),
							(StackType_t * const)OS_TaskStart_Stk, /**/
							(StaticTask_t * const)&OS_TaskStart_Obj); /**/
	vTaskStartScheduler();
}

static uint32 i32RTOS_TaskStkAddr(uint32 u32TskID){
#if TSK_ID_MAX
	uint32 u32Cnt = 0;
    uint32 u32StkAddr = 0;
    if(u32TskID < TSK_ID_MAX){
        u32StkAddr = 0;
        for(u32Cnt = 0;(u32Cnt < TSK_ID_MAX)&&(u32Cnt < u32TskID);u32Cnt++){
            u32StkAddr += ((stSetTskInfoTbl[u32Cnt].u32StackSize) + TASK_STK_RESERVED_INTERVAL);
        }
    }
    else{

    }
    if((u32StkAddr + (stSetTskInfoTbl[TSK_ID_MAX - 1].u32StackSize)) > TASK_STK_TOTAL){
        while(1){
        	portNOP();
            //printf("CreateTask_StackOverflow!!!\n");
        	RTOS_TaskDelay(1000);
        };
    }
    //printf("TaskID[%02d],StkAddr[0x%08x]\n",u32TskID,(&u32TaskStk[0] + u32StkAddr));
    return (uint32)(&u32TaskStk[0] + u32StkAddr);
#else
    return 0;
#endif
}

int32 RTOS_TaskCreate(void){
    int32 i32Rtn = RTOS_ERR_NONE;
#if TSK_ID_MAX
    uint32 u32TaskID = 0;
    for(u32TaskID = 0;u32TaskID < TSK_ID_MAX;u32TaskID++){
    	u32TaskHandle[u32TaskID] = (uint32)xTaskCreateStatic((TaskFunction_t)(stSetTskInfoTbl[u32TaskID].vdFunc),
															(const char * const)(stSetTskInfoTbl[u32TaskID].i8Name),
															(const uint32)stSetTskInfoTbl[u32TaskID].u32StackSize,
															0,
															(UBaseType_t)(((UBaseType_t)stSetTskInfoTbl[u32TaskID].u32Priority) | portPRIVILEGE_BIT ),
															(StackType_t * const)i32RTOS_TaskStkAddr(u32TaskID), /**/
															(StaticTask_t * const)&OS_Task_Obj[u32TaskID]); /**/
    }
#endif
    return i32Rtn;
}


void RTOS_TaskDelay(uint32 millisecond){
	//vTaskDelay(pdMS_TO_TICKS(millisecond));
    vTaskDelay((const TickType_t)millisecond);
}

int32 RTOS_GetTaskId(uint32* u32TaskID_p){
    int32 i32Rtn = RTOS_ERR_NONE;
    if(u32TaskID_p != 0){
        xTaskGetApplicationTaskTag(NULL);
    }
    else{
        i32Rtn = RTOS_ERR_NONE;
    }

    return i32Rtn;
}

uint64 RTOS_GetSystemTick(void){
    return xTaskGetTickCount();
}

uint64 RTOS_GetSystemTick_uS(void){
    return PIT_DRV_GetLifetimeTimerUs(INST_PIT);
}

void RTOS_DI(void){
	taskENTER_CRITICAL();
}

void RTOS_EI(void){
	taskEXIT_CRITICAL();
}


int32 RTOS_QueueCreate(void){
    int32 i32Rtn = RTOS_ERR_NONE;
#if QUEUE_ID_MAX
    uint32 u32Cnt = 0;
    for(u32Cnt = 0;u32Cnt < QUEUE_ID_MAX;u32Cnt++){
        void * pQueueBuffer = NULL;
        pQueueBuffer = pvPortMalloc(stSetQueueInfoTbl[u32Cnt].u32Depth*stSetQueueInfoTbl[u32Cnt].u32Size);
        if(pQueueBuffer != NULL){
            u32QueueHandle[u32Cnt] = (uint32)xQueueCreateStatic((const UBaseType_t)(stSetQueueInfoTbl[u32Cnt].u32Depth),
                                                                (const UBaseType_t)(stSetQueueInfoTbl[u32Cnt].u32Size),
                                                                pQueueBuffer,
                                                                &OS_Queue_Obj[u32Cnt]);
#if ( configQUEUE_REGISTRY_SIZE > 0 )
            {
                if(u32QueueHandle[u32Cnt] != NULL){
                    vQueueAddToRegistry( (QueueHandle_t)u32QueueHandle[u32Cnt], (const char *)(stSetQueueInfoTbl[u32Cnt].i8Name));
                }
            }
#endif
        }
    }
#endif
    return i32Rtn;
}

int32 RTOS_QueuePut(uint32 u32ID,void* vdData_p,uint32 u2Size,uint32 u32Timeout){
    int32 i32Rtn = RTOS_ERR_NONE;
#if QUEUE_ID_MAX
    uint32 u32TimeDelay;
	if((u32ID < QUEUE_ID_MAX)&&(vdData_p != 0)&&(u2Size == stSetQueueInfoTbl[u32ID].u32Size)){
        if(u32Timeout == 0){
            u32TimeDelay = portMAX_DELAY;
        }
        else{
            u32TimeDelay = u32Timeout;
        }
        #if 1
        uint32 interrupt_level = MFSPR(272);
        bool is_isr = (bool)(interrupt_level > 0u);
        if (is_isr)
        {
            i32Rtn = xQueueSendFromISR((QueueHandle_t)u32QueueHandle[u32ID],
                                                    (void * const)vdData_p,
                                                    (BaseType_t * const)0);
        }
        else{
            i32Rtn = xQueueSend((QueueHandle_t)u32QueueHandle[u32ID],
                                            (void * const)vdData_p,
                                            (TickType_t)u32TimeDelay);
        }
        #else
        volatile uint32 u32NestingCnt = 0;
        u32NestingCnt = portDECREMENT_CRITICAL_NESTING();
        //if(u32NestingCnt == 0U){
        if ( portDECREMENT_CRITICAL_NESTING() == 0U ){
            i32Rtn = xQueueSend((QueueHandle_t)u32QueueHandle[u32ID],
                                (void * const)vdData_p,
                                (TickType_t)u32TimeDelay);
        }
        else{
            i32Rtn = xQueueSendFromISR((QueueHandle_t)u32QueueHandle[u32ID],
                                        (void * const)vdData_p,
                                        (BaseType_t * const)0);
        }
        #endif
	    switch(i32Rtn){
	        case pdPASS:
	            i32Rtn = RTOS_ERR_NONE;
	            break;
	        case errQUEUE_FULL:
	            i32Rtn = RTOS_ERR_QUEUE;
	            break;
	        default:
	            i32Rtn = RTOS_ERR_QUEUE;
	            break;
	    }
	}
	else{
		i32Rtn = RTOS_ERR_INVALID_PARAMETER;
	}
#endif
    return i32Rtn;
}

int32 RTOS_QueueGet(uint32 u32ID,void* vdData_p,uint32 u2Size,uint32 u32Timeout){
    int32 i32Rtn = RTOS_ERR_NONE;
#if QUEUE_ID_MAX
    uint32 u32TimeDelay;
	if((u32ID < QUEUE_ID_MAX)&&(vdData_p != 0)&&(u2Size == stSetQueueInfoTbl[u32ID].u32Size)){
        if(u32Timeout == 0){
            u32TimeDelay = portMAX_DELAY;
        }
        else{
            u32TimeDelay = u32Timeout;
        }
        i32Rtn = xQueueReceive((QueueHandle_t)u32QueueHandle[u32ID],
                                (void * const)vdData_p,
                                (TickType_t)u32TimeDelay);
        switch(i32Rtn){
	        case pdPASS:
	            i32Rtn = RTOS_ERR_NONE;
	            break;
	        case errQUEUE_FULL:
	            i32Rtn = RTOS_ERR_QUEUE;
	            break;
	        default:
	            i32Rtn = RTOS_ERR_QUEUE;
	            break;
	    }
	}
	else{
		i32Rtn = RTOS_ERR_INVALID_PARAMETER;
	}
#endif
    return i32Rtn;
}

int32 RTOS_EventCreate(void){
    int32 i32Rtn = RTOS_ERR_NONE;
#if EVENT_ID_MAX
    uint32 u32Cnt = 0;
    for(u32Cnt = 0;u32Cnt < EVENT_ID_MAX;u32Cnt++){
        i32Rtn = OSAL_EventCreate(&u32EventID[u32Cnt],
                                    (const uint8)(stSetEventInfoTbl[u32Cnt].i8Name),
                                    0,
                                    0);
    }
#endif
    return i32Rtn;
}

int32 RTOS_EventSet(uint32 u32ID,uint32 u32Event){
	int32 i32Rtn = RTOS_ERR_NONE;
#if EVENT_ID_MAX
	if(u32ID < EVENT_ID_MAX){
		i32Rtn = OSAL_SetEvent(u32EventID[u32ID],u32Event,OSAL_EVENT_SET_OPT_FLAG_SET,0);
		switch(i32Rtn){
	        case OSAL_ERR_NONE:
	            i32Rtn = RTOS_ERR_NONE;
	            break;
	        case OSAL_ERR_EVENT:
	            i32Rtn = RTOS_ERR_EVENT;
	            break;
	        default:
	            i32Rtn = RTOS_ERR_EVENT;
	            break;
	    }
	}
	else{
		i32Rtn = RTOS_ERR_INVALID_PARAMETER;
	}
#endif
	return i32Rtn;
}

int32 RTOS_EventGet(uint32 u32ID,uint32 u32WaitEvent,uint32* u32Event_p,uint32 u32Option,uint32 u32Timeout){
    int32 i32Rtn = RTOS_ERR_NONE;
#if EVENT_ID_MAX
    uint32 u32Opt = 0;
    if((u32ID < EVENT_ID_MAX)&&(u32WaitEvent != 0)&&(u32Event_p != 0)){
        if(u32Option & RTOS_EVENT_OPT_AND){
            u32Opt = OSAL_EVENT_OPT_SET_ALL;
        }
        else if(u32Option & RTOS_EVENT_OPT_OR){
            u32Opt = OSAL_EVENT_OPT_SET_ANY;
        }
        else{
            u32Opt = OSAL_EVENT_OPT_SET_ANY;
        }
        *u32Event_p = OSAL_GetEvent(u32EventID[u32ID],u32WaitEvent,u32Timeout,u32Opt,&i32Rtn,0);
        switch(i32Rtn){
            case OSAL_ERR_NONE:
                i32Rtn = RTOS_ERR_NONE;
                break;
            case OSAL_ERR_EVENT:
                i32Rtn = RTOS_ERR_EVENT;
                break;
            default:
                i32Rtn = RTOS_ERR_EVENT;
                break;
        }
    }
    else{
        *u32Event_p = 0;
        i32Rtn = RTOS_ERR_INVALID_PARAMETER;
    }
#endif
    return i32Rtn;
}

int32 RTOS_EventClr(uint32 u32ID,uint32 u32Event){
    int32 i32Rtn = RTOS_ERR_NONE;
#if EVENT_ID_MAX
    if(u32ID < EVENT_ID_MAX){
        i32Rtn = OSAL_SetEvent(u32EventID[u32ID],u32Event,OSAL_EVENT_SET_OPT_FLAG_CLR,0);
        switch(i32Rtn){
            case OSAL_ERR_NONE:
                i32Rtn = RTOS_ERR_NONE;
                break;
            case OSAL_ERR_EVENT:
                i32Rtn = RTOS_ERR_EVENT;
                break;
            default:
                i32Rtn = RTOS_ERR_EVENT;
                break;
        }
    }
    else{
        i32Rtn = RTOS_ERR_INVALID_PARAMETER;
    }
#endif
    return i32Rtn;
}




int32 RTOS_SemaphoreCreate(void){
    int32 i32Rtn = RTOS_ERR_NONE;
#if SEMA_ID_MAX
    uint32 u32Cnt = 0;
    for(u32Cnt = 0;u32Cnt < SEMA_ID_MAX;u32Cnt++){
        (void)OSAL_SemaCreate(&u32SemaphoreID[u32Cnt],
                                (const uint8 *)(stSetSemaInfoTbl[u32Cnt].i8Name),
                                stSetSemaInfoTbl[u32Cnt].u32Init,
                                0);
    }
#endif
    return i32Rtn;
}

int32 RTOS_SemaphoreObtain( uint32 u32ID, uint32 u32Timeout){
	int32 i32Rtn = RTOS_ERR_NONE;
#if SEMA_ID_MAX
	if(u32ID < SEMA_ID_MAX){
		i32Rtn = OSAL_SemaObtain(u32SemaphoreID[u32ID], u32Timeout, OSAL_API_OPT_BLOCKING);
		switch(i32Rtn){
			case OSAL_ERR_NONE:
				i32Rtn = RTOS_ERR_NONE;
				break;
			case OSAL_ERR_SEMA:
				i32Rtn = RTOS_ERR_SEMA;
				break;
			default:
				i32Rtn = RTOS_ERR_SEMA;
				break;
		}
	}
	else{
		i32Rtn = RTOS_ERR_INVALID_PARAMETER;
	}
#endif
	return i32Rtn;
}

int32 RTOS_SemaphoreRelease(uint32 u32ID){
	int32 i32Rtn = RTOS_ERR_NONE;
#if SEMA_ID_MAX
	if(u32ID < SEMA_ID_MAX){
		i32Rtn = OSAL_SemaRelease(u32SemaphoreID[u32ID]);
		switch(i32Rtn){
			case OSAL_ERR_NONE:
				i32Rtn = RTOS_ERR_NONE;
				break;
			case OSAL_ERR_SEMA:
				i32Rtn = RTOS_ERR_SEMA;
				break;
			default:
				i32Rtn = RTOS_ERR_SEMA;
				break;
		}
	}
	else{
		i32Rtn = RTOS_ERR_INVALID_PARAMETER;
	}
#endif
	return i32Rtn;
}



int32 RTOS_CycleCreate(void){
    int32 i32Rtn = RTOS_ERR_NONE;
#if CYC_ID_MAX
    TimerHandle_t TimerHandle = 0;
    uint32 u32Cnt = 0;
    for(u32Cnt = 0;u32Cnt < CYC_ID_MAX;u32Cnt++){
        u32CycleID[u32Cnt] = u32Cnt;
        TimerHandle = xTimerCreateStatic((const char * const)(stSetCycleInfoTbl[u32Cnt].i8Name_p),
                                        (const TickType_t)(pdMS_TO_TICKS(stSetCycleInfoTbl[u32Cnt].u32Period)),
                                        (const UBaseType_t)(stSetCycleInfoTbl[u32Cnt].u32Reload),
                                        (void * const)&u32CycleID[u32Cnt],
                                        (TimerCallbackFunction_t)RTOS_Cycle_TimerCallback,
                                        (StaticTimer_t *)&OS_Timer_Obj[u32Cnt]);
        u32CycleHandle[u32Cnt] = (uint32)TimerHandle;
        (void)xTimerStart((TimerHandle_t)TimerHandle,0);
    }
#endif
    return i32Rtn;
}

static void RTOS_Cycle_TimerCallback(TimerHandle_t xTimer){
    uint32 *u32TimerId_p;
    uint32 u32TimerId;
    configASSERT( xTimer );

    /* Get the timer ID */
    u32TimerId_p = ( uint32 * )pvTimerGetTimerID( xTimer );
    u32TimerId = *u32TimerId_p;

    /* Execute the timer handler function */
    if (stSetCycleInfoTbl[u32TimerId].Cb_Func_p != NULL)
    {
        /* The timer does not reload automatically */
        if (stSetCycleInfoTbl[u32TimerId].u32Reload == FALSE)
        {
            xTimerStop((TimerHandle_t)u32CycleHandle[u32TimerId], (const TickType_t)NULL);
        }
        else
        {
            /* NOP */
        }
        stSetCycleInfoTbl[u32TimerId].Cb_Func_p();
    }
    else
    {
        xTimerStop((TimerHandle_t)u32CycleHandle[u32TimerId], (const TickType_t)NULL);
    }


}

void RTOS_MemSet(void *pmem,uint8 val,uint32 size){
    if((pmem != 0)&&(size > 0)){
        (void) memset(pmem, (int32)val, (size_t)size); //QAC-Not use return value
    }
}

void RTOS_MemCopy(void *pdest,const void *psrc,uint32 size){
    if((pdest != 0)&&(psrc !=0)&&(size > 0)){
        (void) memcpy(pdest,(const void *)psrc,(size_t)size); //QAC-Not use return value
    }
}

int32 RTOS_MemCmp(const void *pmem1, const void *pmem2, uint32 size){
    int32 ret = 0;
    if((pmem1 != 0)&&(pmem2 != 0)&&(size > 0)){
        ret = memcmp(pmem1, pmem2, (size_t)size); //QAC-Not use return value
    }
    return ret;
}

/*String*/
int8 * RTOS_StrCopy(uint8 *dest_str,const uint8 *src_srt){
    int8 * ret = 0;
    if ((dest_str !=0)&&(src_srt !=0)){
        ret = strcpy((int8*)dest_str,(const int8*)src_srt);
    }
    return ret;
}

int16 RTOS_StrCmp(const uint8 *p1,const uint8 *p2){
    int16 ret = -1;
    if((p1 !=0)&&(p2 !=0)){
        ret = (int16)strcmp((const int8 *)p1,(const int8 *)p2);
    }
    return ret;
}

int16 RTOS_StrNCmp(const uint8 *p1, const uint8 *p2, int32 len){
    int16 ret = -1;
    if ( (p1 !=0) && (p2 !=0) && (len>0)){
        ret = (int16)strncmp((const int8 *)p1, (const int8 *)p2, (uint32)len);
    }
    return ret;
}

uint32 RTOS_StrLen(const uint8 *pstr){
    uint32 ret = 0;
    if ( pstr !=0){
        ret = strlen((const int8 *)pstr);
    }
    return ret;
}

void WKPU_31_24_IRQHandler(void){
	portNOP();

}




/* End of File */
